using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Xml;

using Microsoft.Win32;//注册表操作要引用的空间

namespace holysheng.RegeditX
{
    #region 基类、接口，基本不再改变，适用于将来扩展




    // 重写Environment，改变path环境变量的返回值为未解析的字符串
    public static class EnvironmentX
    {
        public static IDictionary GetEnvironmentVariables(EnvironmentVariableTarget target)
        {
            switch (target)
            {
                case EnvironmentVariableTarget.Machine:
                    {
                        using (RegistryKey registryKey2 = Registry.LocalMachine.OpenSubKey("System\\CurrentControlSet\\Control\\Session Manager\\Environment", writable: false))
                        {
                            return GetRegistryKeyNameValuePairs(registryKey2);
                        }
                    }
                case EnvironmentVariableTarget.User:
                    {
                        using (RegistryKey registryKey = Registry.CurrentUser.OpenSubKey("Environment", writable: false))
                        {
                            return GetRegistryKeyNameValuePairs(registryKey);
                        }
                    }
                default:
                    throw new ArgumentException();
            }
        }
        internal static IDictionary GetRegistryKeyNameValuePairs(RegistryKey registryKey)
        {
            Hashtable hashtable = new Hashtable(20);
            if (registryKey != null)
            {
                string[] valueNames = registryKey.GetValueNames();
                string[] array = valueNames;
                foreach (string text in array)
                {
                    string value = registryKey.GetValue(text, "", RegistryValueOptions.DoNotExpandEnvironmentNames).ToString();
                    hashtable.Add(text, value);
                }
            }

            return hashtable;
        }
    }

    // 环境变量基类，包含变量名、变量值
    // 增加了内存中的状态，用于保存时对原记录的增、删、改的决定
    public class BaseReg
    {
        public enum RegStatus { Original, AddReg, ChangeReg, DelReg }
        private string _regVar;
        private string _regValue;
        private RegStatus _status = RegStatus.Original;

        // 环境变量名
        public string RegVar
        {
            get { return _regVar; }
            set { _regVar = value; }
        }

        // 环境变量值
        public string RegValue
        {
            get
            {
                return _regValue;
            }
            set
            {
                _regValue = value;
            }
        }

        /*
         * 理想的状态功能：待探索解决方案
         *      Original：略过，原有数据内存中未改变，
         *      AddReg：添加，内存中有新增数据，将同时在注册表中新增，
         *      ChangeReg：修改，原有数据内存中被改变，将改变原有数据，
         *      DelReg：删除，原有数据内存中被删除，将删除注册表原始数据。
         *       
         */
        /// <summary>
        /// 对于状态，只存在于原为Original的，其它均为AddReg状态，通过内存添加后再删除的环境变量，将直接从内存中删除，
        /// 内存中注册表细目的状态，此属性决定在保存注册表或XML文件时的操作方法（增、删、改），
        /// </summary>
        public RegStatus Status
        {
            get { return _status; }
            set { _status = value; }
        }
    }

    // 环境变量基类扩展，继承自BaseReg
    // 增加了比较方法Equals()
    public class Reg : BaseReg, IEquatable<Reg>, IEquatable<string>
    {
        public Reg()
        {
            RegVar = "";
            RegValue = "";
            Status = RegStatus.AddReg;
        }
        public Reg(string regVar, string regValue)
        {
            RegVar = regVar;
            RegValue = regValue;
            Status = RegStatus.AddReg;
        }
        public Reg(string regVar, string regValue, RegStatus status)
        {
            RegVar = regVar;
            RegValue = regValue;
            Status = status;
        }

        // 不区分大小写，同时判断变量名和值
        public bool Equals(Reg other)
        {
            //this非空，obj如果为空，则返回false
            if (other is null)
                return false;

            //如果为同一对象，必然相等
            if (ReferenceEquals(this, other))
                return true;

            string oldvar = RegVar.ToLower();
            string oldvalue = RegValue.ToLower();
            string othervar = other.RegVar.ToLower();
            string othervalue = other.RegValue.ToLower();

            //对比各个字段值
            if (oldvar == othervar && oldvalue == othervalue)
                return true;

            return false;
        }

        // 不区分大小写，只判断变量名
        public bool Equals(string name)
        {
            //this非空，obj如果为空，则返回false
            if (name is null)
                return false;


            string oldvar = RegVar.ToLower();
            string othervar = name.ToLower();

            //对比name值
            if (oldvar == othervar)
                return true;

            return false;
        }
    }

    // 接口，定义了内存中Reg集合的增、删、改、查、绑定
    public interface IRegBindingList
    {
        /// <summary>
        /// 将环境变量Reg添加到Reg集合（只涉及内存），此处要区分：是首次读取，还是后面添加
        /// 首次读取状态为Original
        /// 后面添加状态为AddReg
        /// </summary>
        bool AddReg(Reg other, Reg.RegStatus status);

        /// <summary>
        /// 将变量名和变量值添加到Reg集合（只涉及内存）
        /// 首次读取状态为Original
        /// 后面添加状态为AddReg
        /// </summary>
        bool AddReg(string regVar, string regValue, Reg.RegStatus status);

        /// <summary>
        /// 从Reg集合中删除环境变量Reg（只涉及内存）
        /// </summary>
        bool DelReg(string name);

        /// <summary>
        /// 从Reg集合中删除环境变量Reg（只涉及内存）
        /// </summary>
        bool DelReg(Reg other);

        /// <summary>
        /// 编缉Reg集合的元素：查找Reg集合中，Reg.Var为oldReg.Var和newReg.Var的元素是否存在，再将新值替换为旧值（只涉及内存）
        /// </summary>
        bool EditReg(Reg oldReg, Reg newReg);

        bool EditReg(string oldRegVar, string oldRegValue, string newRegVar, string newRegValue);

        /// <summary>
        /// 查找Reg集合中，Var为name的值是否存在（只涉及内存）
        /// </summary>
        int FindRegVar(string name);

        /// <summary>
        /// 查找Reg集合中，Var为name的值是否存在（只涉及内存）
        /// </summary>
        int FindRegVar(Reg other);

        /// <summary>
        /// 通过内存中的Reg集合，用于数据源绑定（只涉及内存）
        /// </summary>
        BindingSource BindingDataSource();
    }

    // 实现IRegBindingList接口
    public class RegBindingList : IRegBindingList // 无须再继承 BindingList<Reg>接口，因为本身就是操作的BindingList<Reg>
    {
        private BindingList<Reg> _regList = new BindingList<Reg>();
        public BindingList<Reg> GetRegList
        {
            get { return _regList; }
        }

        // 只比对变量名
        public static bool CanAddRegVar(BindingList<Reg> regList, Reg otherReg)
        {
            foreach (Reg reg in regList)
            {
                if (reg.Equals(otherReg.RegVar))
                {
                    return false;
                }
            }
            return true;
        }

        // 只比对变量名
        public static bool CanAddRegVar(BindingList<Reg> regList, string regVar)
        {
            foreach (Reg reg in regList)
            {
                if (reg.Equals(regVar))
                {
                    return false;
                }
            }
            return true;
        }

        // 只比对变量名
        public static bool CanDelRegVar(BindingList<Reg> regList, string regVar)
        {
            foreach (Reg reg in regList)
            {
                if (reg.Equals(regVar))
                {
                    return false;
                }
            }
            return true;
        }

        // 只比对变量名
        public static bool CanEditReg(BindingList<Reg> regList, string oldRegVar, string newRegVar)
        {
            Reg rOld = null;
            Reg rNew = null;
            foreach (Reg r in regList)// 只遍历一次，分别找到旧值和新值
            {
                if (r.Equals(oldRegVar))
                {
                    rOld = r;
                }
                if (r.Equals(newRegVar))
                {
                    rNew = r;
                }
            }
            if (rOld == null)// 如旧值未找到，则无法编缉
            {
                return false;
            }
            else if (rNew != null && rOld.RegVar != rNew.RegVar) // 如旧值、新值都找到，且Var不是同一个，说明新值存在重复
            {
                return false;
            }
            return true;
        }

        // 只比对变量名
        public static bool CanEditReg(BindingList<Reg> regList, Reg oldReg, Reg newReg, ref Reg rOld, ref Reg rNew)
        {
            foreach (Reg r in regList)// 只遍历一次，分别找到旧值和新值
            {
                if (r.Equals(oldReg.RegVar))
                {
                    rOld = r;
                }
                if (r.Equals(newReg.RegVar))
                {
                    rNew = r;
                }
            }
            if (rOld == null)// 旧值未找到，则无法编缉，还要判断新值是否找到
            {
                return false;
            }
            else if (rNew != null && rOld.RegVar != rNew.RegVar) // 新值找到，但Var不是同一个，说明新值存在重复
            {
                return false;
            }
            return true; // 新值未找到
        }

        public bool AddReg(Reg other, Reg.RegStatus status)
        {
            if (CanAddRegVar(_regList, other))
            {
                other.Status = status;
                _regList.Add(other);
                return true;
            }
            return false;
        }

        public bool AddReg(string regVar, string regValue, Reg.RegStatus status)
        {
            if (CanAddRegVar(_regList, regVar))
            {
                Reg newReg = new Reg
                {
                    RegVar = regVar,
                    RegValue = regValue,
                    Status = status
                };
                _regList.Add(newReg);
                return true;
            }
            return false;
        }

        // 只比对RegVar，目前是直接从集合中删除
        public bool DelReg(string name)
        {
            foreach (Reg r in _regList)
            {
                if (r.Equals(name))
                {
                    r.Status = Reg.RegStatus.DelReg;//此处增加状态，是为防止同步失败
                    _regList.Remove(r);
                    return true;
                }
            }
            return false;
        }

        // 只比对RegVar，目前是直接从集合中删除
        public bool DelReg(Reg other)
        {
            foreach (Reg reg in _regList)
            {
                if (reg.Equals(other.RegVar))
                {
                    reg.Status = Reg.RegStatus.DelReg;//此处增加状态，是为防止同步失败
                    _regList.Remove(reg);
                    return true;
                }
            }
            return false;
        }

        public bool EditReg(Reg oldReg, Reg newReg)
        {
            // 未改变，变量与值都最相等，直接返回true
            if (oldReg.Equals(newReg))
            {
                return true;
            }
            Reg rOld = null;
            Reg rNew = null;

            if (CanEditReg(_regList, oldReg, newReg, ref rOld, ref rNew)) // 在调用函数里已做判断，还余新值未找到、Var是同一个判断
            {
                if (rNew == null) // 完全新值，两者都要改
                {
                    rOld.RegVar = newReg.RegVar;
                    rOld.RegValue = newReg.RegValue;
                    rOld.Status = Reg.RegStatus.AddReg; // 全新，所以改状态为AddReg
                }
                else if (oldReg.Equals(newReg.RegVar)) // 新值找到且与旧值的变量名相同，则只须更改Value
                {
                    rOld.RegValue = newReg.RegValue;
                    rOld.Status = Reg.RegStatus.ChangeReg; // 改修改状态
                }
                return true;
            }
            return false;
        }


        public bool EditReg(string oldRegVar, string oldRegValue, string newRegVar, string newRegValue)
        {
            Reg oldReg = new Reg();
            Reg newReg = new Reg();
            oldReg.RegVar = oldRegVar;
            oldReg.RegValue = oldRegValue;
            newReg.RegVar = newRegVar;
            newReg.RegValue = newRegValue;
            return EditReg(oldReg, newReg);
        }

        // 只查找RegVar相同的对象
        public int FindRegVar(string name)
        {
            foreach (Reg reg in _regList)
            {
                if (reg.Equals(name))
                {
                    return _regList.IndexOf(reg);
                }
            }
            return -1;
        }

        // 只查找RegVar相同的对象
        public int FindRegVar(Reg other)
        {
            foreach (Reg reg in _regList)
            {
                if (reg.Equals(other))
                {
                    return _regList.IndexOf(reg);
                }
            }
            return -1;
        }

        public BindingSource BindingDataSource()
        {
            try
            {
                _regList.AllowNew = true;
                _regList.AllowRemove = true;
                _regList.AllowEdit = true;
                return new BindingSource(_regList, null);
            }
            catch (Exception ex)
            {
                MessageBox.Show("绑定失败，错误代码为：" + ex.ToString());
                return null;
            }
        }
    }

    #endregion

    #region 本程序专用，只须实例化TwoRegBindingList，或TwoRegBindingListAndName类，即可操作注册表和XML设置文件

    // 该类具有2个BindingList 
    public class TwoRegBindingList
    {
        private RegBindingList user = new RegBindingList();

        // 系统环境变量
        private RegBindingList system = new RegBindingList();

        public RegBindingList User
        {
            get { return user; }
        }
        public RegBindingList System
        {
            get { return system; }
        }
    }


    // 在TwoRegBindingList类的基础上，增加了Name属性。
    public class TwoRegBindingListAndName : TwoRegBindingList
    {
        private string name;

        public string Name
        {
            get { return name; }
            set { name = value; }
        }
    }

    // 因为还需要遍历每一个包含Name的集合，所以须继承BindingList<>，否则不能用foreach
    public class RegXMLList : BindingList<TwoRegBindingListAndName>
    {
        private BindingList<TwoRegBindingListAndName> _nameList = new BindingList<TwoRegBindingListAndName>();//用于保存读取的整个环境变量配置文件

        public BindingList<TwoRegBindingListAndName> NameList
        {
            get { return _nameList; }
        }
        public void AddName()
        {
            TwoRegBindingListAndName newName = new TwoRegBindingListAndName
            {
                Name = "新的设置名"
            };
            _nameList.Add(newName);
        }
    }

    #endregion

    // TwoRegBindingList类的扩展，包含操作注册表的特有方法：读取、保存、加载
    // 使用方法，new一个RegComputer，里面包含user、system对象，再具体操作即可
    public class RegComputer : TwoRegBindingList
    {
        #region 初使化
        public RegComputer()
        {
            LoadReg();
        }

        /// 读取计算机中的环境变量，返回RegBindingList
        private bool LoadReg()
        {
            try
            {
                IDictionary envir;//键值对的集合
                Reg reg;//具体的对像

                //用户环境变量
                envir = EnvironmentX.GetEnvironmentVariables(EnvironmentVariableTarget.User);
                foreach (object key in envir.Keys)
                {
                    reg = new Reg
                    {
                        RegVar = key.ToString(),//设置环境变量名
                        RegValue = envir[key].ToString(),//设置环境变量值
                        Status = Reg.RegStatus.Original//默认为原始数据
                    };
                    if (!User.AddReg(reg, BaseReg.RegStatus.Original))
                    {
                        Debug.WriteLine("读取用户环境变量时，新增错误");
                    }
                }

                //系统环境变量
                envir = EnvironmentX.GetEnvironmentVariables(EnvironmentVariableTarget.Machine);
                foreach (object key in envir.Keys)
                {
                    reg = new Reg
                    {
                        RegVar = key.ToString(),//设置环境变量名
                        RegValue = envir[key].ToString(),//设置环境变量值
                        Status = Reg.RegStatus.Original//默认为原始数据
                    };
                    if (!System.AddReg(reg, BaseReg.RegStatus.Original))
                    {
                        Debug.WriteLine("读取系统环境变量时，新增错误");
                    }
                }
                return true;
            }
            catch (Exception ex)
            {
                MessageBox.Show("读取计算机环境变量错误：" + ex.ToString());
                return false;
            }
        }
        #endregion

        #region 用于计算机注册表的绑定方式
        public bool BindingDataSource(DataGridView user, DataGridView system)
        {
            try
            {
                user.DataSource = User.BindingDataSource();
                system.DataSource = System.BindingDataSource();
                return true;
            }
            catch (Exception ex)
            {
                MessageBox.Show("绑定失败，错误代码为：" + ex.ToString());
                return false;
            }
        }
        #endregion

        #region 保存
        // Original：略过，原有数据内存中未改变，
        // AddReg：添加，内存中有新增数据，将同时在注册表中新增，
        // ChangeReg：修改，原有数据内存中被改变，将改变原有数据，
        // DelReg：删除，原有数据内存中被删除，将删除注册表原始数据。

        // 将内存中的用户环境变量，保存到注册表
        // TODO 生成的paht环境变量，不能即时生效，须打开注册表，修改一下再保存？？？？？？？？？
        public bool SaveUserReg()
        {
            RegComputer computer = new RegComputer();
            try
            {
                foreach (Reg uReg in this.User.GetRegList) // 遍历内存：在外围循环，因为有状态，可以加快速度
                {
                    if (uReg.Status == Reg.RegStatus.Original) // 判断原注册表是否有被修改，可加快遍历速度
                    {
                        continue;
                    }
                    if (uReg.Status == Reg.RegStatus.AddReg || uReg.Status == Reg.RegStatus.ChangeReg) // 状态为添加、修改
                    {
                        using (RegistryKey registryKey = Registry.CurrentUser.OpenSubKey("Environment", true))
                        {
                            RegistryValueKind kind = uReg.RegValue.Contains("%") ? RegistryValueKind.ExpandString : RegistryValueKind.String;
                            registryKey.SetValue(uReg.RegVar, uReg.RegValue, kind);
                            registryKey.Close();
                        }
                    }
                }

                foreach (Reg cuReg in computer.User.GetRegList) // 遍历注册表，如果注册表有，但内存中没有，则删除
                {
                    if (User.FindRegVar(cuReg.RegVar) == -1)
                    {
                        Environment.SetEnvironmentVariable(cuReg.RegVar, null, EnvironmentVariableTarget.User); // 删除注册表
                    }
                }
                return true;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
                Debug.WriteLine(ex.ToString());
                return false;
            }
        }

        //将内存中的系统环境变量，保存到注册表
        public bool SaveSystemReg()
        {
            RegComputer computer = new RegComputer();
            foreach (Reg uReg in this.System.GetRegList) // 遍历内存：在外围循环，因为有状态，可以加快速度
            {
                if (uReg.Status == Reg.RegStatus.Original) // 判断原注册表是否有被修改，可加快遍历速度
                {
                    continue;
                }
                if (uReg.Status == Reg.RegStatus.AddReg || uReg.Status == Reg.RegStatus.ChangeReg) // 状态为添加、修改
                {
                    using (RegistryKey registryKey = Registry.LocalMachine.OpenSubKey("System\\CurrentControlSet\\Control\\Session Manager\\Environment", true))
                    {
                        RegistryValueKind kind = uReg.RegValue.Contains("%") ? RegistryValueKind.ExpandString : RegistryValueKind.String;
                        registryKey.SetValue(uReg.RegVar, uReg.RegValue, kind);
                        registryKey.Close();
                    }
                }
            }

            foreach (Reg cuReg in computer.System.GetRegList) // 遍历注册表，如果注册表有，但内存中没有，则删除
            {
                if (System.FindRegVar(cuReg.RegVar) == -1)
                {
                    Environment.SetEnvironmentVariable(cuReg.RegVar, null, EnvironmentVariableTarget.Machine); // 删除注册表
                }
            }
            return true;
        }
        #endregion
    }

    // TwoRegBindingListAndName类的扩展，包含操作XML文件的特有方法：读取、创建、保存、加载xml文件，查找配置名
    // 使用方法，new一个RegXML，里面一个TwoRegBindingListAndName集合，每个集合元素包含user、system对象和Name属性，再具体操作即可
    public class RegXML : RegXMLList
    {
        #region 初使化
        private bool REPEAT = false; // 用于判断程序是否进入无限循环创建配置文件过程中
        public RegXML()
        {
            LoadXMLFile();
        }

        public RegXML(string path)
        {
            LoadXMLFile(path);
        }

        /// <summary>
        /// 读取XML文件，如未指定文件名和路径，则默认为TreeXml.xml
        /// </summary>
        private bool LoadXMLFile()
        {
            return LoadXMLFile("TreeXml.xml");
        }
        /// <summary>
        /// 根据指定的路径，读取XML文件，
        /// 如该路径的文件不存在，则读取程序所在路径的TreeXml.xml文件，
        /// 如TreeXml.xml也不存在，则自动创建。
        private bool LoadXMLFile(string pathFile)
        {
            #region 判断文件是否存在
            string xmlFile = "TreeXml.xml";//默认文件名
            if (File.Exists(pathFile))
            {
                xmlFile = pathFile;//如指定文件名存在，则用指定的文件名路径
            }
            else if (!File.Exists(xmlFile))
            {
                //如果TreeXml.xml也不存在，则创建TreeXml.xml文件，并重新调用当前方法
                if (CreatXMLFile())
                {
                    MessageBox.Show("配置文件TreeXml.xml创建成功");
                    return LoadXMLFile();
                }
                return false;//如果文件创建失败，返回false
            }
            #endregion

            XmlDocument xmldoc = new XmlDocument();//XML文档

            // 开始读取XML文件，共4层
            // 1、根
            // 2、设置名
            // 3、user 和 system
            // 4、详细的环境变量
            xmldoc.Load(xmlFile);
            XmlNode xmlNode = xmldoc.DocumentElement;//读取XML文档的根
            if (xmlNode.ChildNodes.Count == 0 || !ReadXMLChildNodes(xmlNode)) // 如果不存在设置名，或读取详细配置出错，则重新创建配置文件
            {
                if (REPEAT)
                {
                    MessageBox.Show("文件读写错误，请联系软件作者");
                    Process.GetCurrentProcess().Kill();//此方法完全奏效，绝对是完全退出
                }
                CreatXMLFile();
                REPEAT = true; // 防止程序进行死循环
                LoadXMLFile();
                return true;
            }
            return true;
        }

        private bool ReadXMLChildNodes(XmlNode xmlNode)
        {
            try
            {
                //读取XML文件
                foreach (XmlNode nodeName in xmlNode.ChildNodes)//读取第2层，遍历设置名称
                {
                    TwoRegBindingListAndName twoRegBindingListAndName = new TwoRegBindingListAndName()
                    {
                        Name = nodeName.Attributes["Name"].Value//获得设置名称
                    };
                    foreach (XmlNode nodeRegPermissions in nodeName.ChildNodes)//读取第3层，读取user 和 system
                    {
                        string per = nodeRegPermissions.Attributes["RegPermissions"].Value;//判断属 user 还是 system
                        if (per == "user")
                        {
                            foreach (XmlNode nodeValue in nodeRegPermissions.ChildNodes)//遍历详细的环境变量
                            {
                                Reg reg = new Reg
                                {
                                    RegVar = nodeValue.Attributes["Var"].Value,//获得变量名
                                    RegValue = nodeValue.Attributes["Value"].Value,//获得变量值
                                    Status = Reg.RegStatus.Original//添加默认状态
                                };//具体的Reg对像
                                twoRegBindingListAndName.User.AddReg(reg, BaseReg.RegStatus.Original);//添加user环境变量
                            }
                        }
                        else if (per == "system")
                        {
                            foreach (XmlNode nodeValue in nodeRegPermissions.ChildNodes)//遍历详细的环境变量
                            {
                                Reg reg = new Reg
                                {
                                    Status = Reg.RegStatus.Original,//添加默认状态
                                    RegVar = nodeValue.Attributes["Var"].Value,//获得变量名
                                    RegValue = nodeValue.Attributes["Value"].Value//获得变量值
                                };//具体的Reg对像
                                twoRegBindingListAndName.System.AddReg(reg, BaseReg.RegStatus.Original);//添加系统环境变量
                            }
                        }
                        // 除了user、system 其它不作判断，以防用户手动修改xml文件，导致程序出错
                    }
                    NameList.Add(twoRegBindingListAndName);//按设置名分类，将twoRegBindingListAndName添加到集合中
                }
                return true;
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
                return false;
            }
        }

        /// <summary>
        /// 重新创建默认配置文件，如配置文件已存在，则会删除重写
        /// </summary>
        /// <returns>成功返回true</returns>
        private bool CreatXMLFile()
        {
            try
            {
                string xmlFile = "TreeXml.xml";

                //如果默认文件存在，但还是调用了本方法，说明配置文件有错误，将删除并重建文件
                if (System.IO.File.Exists(xmlFile))
                {
                    File.Delete(xmlFile);
                }

                //创建文件
                System.IO.FileStream f = System.IO.File.Create(xmlFile);
                f.Close();
                f.Dispose();

                //添加XML文件头部内容
                string str = @"<?xml version=""1.0"" encoding=""UTF-8""?>
<Setting>
	 <Node Name=""holysheng"">
		<Node RegPermissions=""user"">
			<Node Var=""GOCACHE"" Value=""D:\Soft\GoBuild""></Node>
			<Node Var=""Path"" Value=""%PYTHON%;%PYTHON%\Scripts;%GOROOT%;%GOROOT%\bin;%GOBIN%;%NODE_HOME%;%nodejsGloble%\node_globle;%nodejsGloble%\yarn_globle;%nodejsGloble%\pnpm_globle;%nodejsCache%\node_cache;%nodejsCache%\yarn_cache;%nodejsCache%\pnpm_cache;%Git%\bin;%Git%\mingw64;%Git%\mingw64\libexec;%Git%\usr\bin;%TortoiseGit%\bin;%MySQL%\bin;D:\绿色软件\编程工具\数据库\SQLite（数据库）;%USERPROFILE%\AppData\Local\Microsoft\WindowsApps;%USERPROFILE%\.dotnet\tools""></Node>
			<Node Var=""TEMP"" Value=""%USERPROFILE%\AppData\Local\Temp""></Node>
			<Node Var=""GO111MODULE"" Value=""on""></Node>
			<Node Var=""nodejsGloble"" Value=""D:\Soft\nodejsPath\nodejsGloble""></Node>
			<Node Var=""MySQL"" Value=""D:\Soft\MySQL""></Node>
			<Node Var=""GOPATH"" Value=""D:\Soft\GoPath;""></Node>
			<Node Var=""NVM_SYMLINK"" Value=""D:\Soft\nodejs""></Node>
			<Node Var=""PYTHON"" Value=""D:\Soft\python\python2""></Node>
			<Node Var=""TortoiseGit"" Value=""D:\Soft\TortoiseGit""></Node>
			<Node Var=""WORKON_HOME"" Value=""PIPENV_VENV_IN_PROJEC""></Node>
			<Node Var=""GOENV"" Value=""D:\Soft\GoEnv""></Node>
			<Node Var=""TMP"" Value=""%USERPROFILE%\AppData\Local\Temp""></Node>
			<Node Var=""GOBIN"" Value=""D:\Soft\GoPath\bin""></Node>
			<Node Var=""GOPROXY"" Value=""https://goproxy.cn,https://mirrors.aliyun.com/goproxy,https://goproxy.io,https://gocenter.io,direct""></Node>
			<Node Var=""GOROOT"" Value=""D:\Soft\Go""></Node>
			<Node Var=""NODE_HOME"" Value=""D:\Soft\nodejs""></Node>
			<Node Var=""nodejsCache"" Value=""D:\Soft\nodejsPath\nodejsCache""></Node>
			<Node Var=""Git"" Value=""D:\Soft\Git""></Node>
		</Node>
		<Node RegPermissions=""system"">
			<Node Var=""PROCESSOR_REVISION"" Value=""7100""></Node>
			<Node Var=""ComSpec"" Value=""%SystemRoot%\system32\cmd.exe""></Node>
			<Node Var=""TEMP"" Value=""%SystemRoot%\TEMP""></Node>
			<Node Var=""PROCESSOR_LEVEL"" Value=""23""></Node>
			<Node Var=""USERNAME"" Value=""SYSTEM""></Node>
			<Node Var=""DriverData"" Value=""C:\Windows\System32\Drivers\DriverData""></Node>
			<Node Var=""PATHEXT"" Value="".COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC""></Node>
			<Node Var=""Path"" Value=""C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;D:\Program Files\TortoiseGit\bin;C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\;C:\Program Files\Microsoft SQL Server\150\Tools\Binn\;d:\Program Files\Microsoft VS Code\bin;C:\Program Files\NVIDIA Corporation\NVIDIA NvDLISR;C:\Program Files\dotnet\""></Node>
			<Node Var=""NUMBER_OF_PROCESSORS"" Value=""12""></Node>
			<Node Var=""TMP"" Value=""%SystemRoot%\TEMP""></Node>
			<Node Var=""windir"" Value=""%SystemRoot%""></Node>
			<Node Var=""PROCESSOR_ARCHITECTURE"" Value=""AMD64""></Node>
			<Node Var=""PSModulePath"" Value=""%ProgramFiles%\WindowsPowerShell\Modules;%SystemRoot%\system32\WindowsPowerShell\v1.0\Modules""></Node>
			<Node Var=""PROCESSOR_IDENTIFIER"" Value=""AMD64 Family 23 Model 113 Stepping 0, AuthenticAMD""></Node>
			<Node Var=""OS"" Value=""Windows_NT""></Node>
		</Node>
	</Node>
</Setting>";
                StringBuilder stringbuilder = new StringBuilder();
                stringbuilder.Append(str);
                StreamWriter sr = new StreamWriter(xmlFile, false, System.Text.Encoding.UTF8);
                sr.Write(stringbuilder.ToString());
                sr.Close();
                MessageBox.Show("加载配置文件TreeXml.xml出错，已重新创建");
                return true;
            }
            catch (Exception ex)
            {
                MessageBox.Show("文件创建失败，错误代码为：" + ex.ToString());
                Process.GetCurrentProcess().Kill();//此方法完全奏效，绝对是完全退出
                return false;
            }
        }
        #endregion

        #region 用于XML的三种绑定方式

        /// <summary>
        /// 对于DataGridView，最终都最调用RegBindingList的 BindingDataSource() 静态方法
        /// </summary>
        /// <param name="treeView">TreeView控件</param>
        /// <param name="user">DataGridView控件</param>
        /// <param name="system">DataGridView控件</param>
        /// <returns>绑定成功返回true</returns>
        public bool BindingDataSource(TreeView treeView, DataGridView user, DataGridView system)
        {

            if (BindingDataSource(treeView) && BindingDataSource(user, system, 0))
            {
                return true;
            }
            return false;
        }

        //绑定TreeView
        public bool BindingDataSource(TreeView treeView)
        {
            try
            {
                treeView.Nodes.Clear();//先清空节点
                TreeNode new_child;
                foreach (TwoRegBindingListAndName xmlReg in NameList)
                {
                    new_child = new TreeNode
                    {
                        Text = xmlReg.Name

                    };//定义一个TreeNode节点对象

                    treeView.Nodes.Add(new_child);//向当前TreeNodeCollection集合中添加当前节点
                }
                return true;
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
                return false;
            }
        }

        //绑定两个DataGridView，此处如果用查找Name的方式，再绑定，效率会比较低，所以直接用的索引方式绑定
        public bool BindingDataSource(DataGridView user, DataGridView system, int index)
        {
            try
            {

                if (BindingDataSource(user, NameList[index].User) && BindingDataSource(system, NameList[index].System))
                {
                    return true;
                }
                return false;
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
                return false;
            }
        }

        public bool BindingDataSource(DataGridView datagridview, RegBindingList list)
        {
            try
            {
                datagridview.DataSource = list.BindingDataSource();
                return true;
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
                return false;
            }
        }
        #endregion

        #region 加载、查找设置名、保存
        /// <summary>
        /// 用于查找指定的配置名是否存在，找到返回索引，未找到返回-1
        /// </summary>
        public int FindName(string name)
        {
            foreach (TwoRegBindingListAndName rName in NameList)
            {
                if (rName.Name == name)
                {
                    return NameList.IndexOf(rName);
                }
            }
            return -1;
        }

        /// <summary>
        /// 用于删除指定名字的配置，成功返回true
        /// </summary>
        public bool DelName(string name)
        {
            foreach (TwoRegBindingListAndName rName in NameList)
            {
                if (rName.Name == name)
                {
                    return NameList.Remove(rName);
                }
            }
            return false;
        }

        //将内存中的环境变量，保存到XML文件中
        public bool SaveReg()
        {
            try
            {
                string xmlFile = "TreeXml.xml";

                //如果默认文件存在，但还是调用了本方法，说明配置文件有错误，将删除并重建文件
                if (System.IO.File.Exists(xmlFile))
                {
                    File.Delete(xmlFile);
                }

                //创建文件
                System.IO.FileStream f = System.IO.File.Create(xmlFile);
                f.Close();
                f.Dispose();

                //添加XML文件头部内容
                string str = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Setting>\n";

                foreach (TwoRegBindingListAndName rName in NameList)//读取设置名
                {
                    str = str + "\t <Node Name=\"" + rName.Name + "\">\n";
                    str += "\t\t<Node RegPermissions=\"user\">\n";//读取user
                    foreach (Reg user in rName.User.GetRegList)
                    {
                        str = str + "\t\t\t<Node Var=\"" + user.RegVar + "\" Value=\"" + user.RegValue + "\"></Node>\n";//读取详细的环境变量
                    }
                    str += "\t\t</Node>\n";//闭合user

                    str += "\t\t<Node RegPermissions=\"system\">\n";//读取system
                    foreach (Reg system in rName.System.GetRegList)
                    {
                        str = str + "\t\t\t<Node Var=\"" + system.RegVar + "\" Value=\"" + system.RegValue + "\"></Node>\n";//读取详细的环境变量
                    }
                    str += "\t\t</Node>\n";//闭合system
                    str += "\t</Node>\n";//闭合name
                }
                str += "</Setting>";

                StringBuilder stringbuilder = new StringBuilder();
                stringbuilder.Append(str);
                StreamWriter sr = new StreamWriter(xmlFile, false, System.Text.Encoding.UTF8);
                sr.Write(stringbuilder.ToString());
                sr.Close();
                return true;
            }
            catch (Exception ex)
            {
                MessageBox.Show("文件创建失败，错误代码为：" + ex.ToString());
                return false;
            }
        }
        #endregion
    }
}
